package spring.cloud.study.hystrix;

import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

import spring.cloud.study.entity.base.ResponseModel;
import spring.cloud.study.feign.ConsumerFeignClient;

@Service
public class HystrixService {

	private static final Logger logger = LoggerFactory.getLogger(HystrixService.class);

	@Autowired
	RestTemplate restTemplate;

	@Autowired
	private ConsumerFeignClient feignClient;

	/**
	 * @throws Exception 远程调用 若调用服务宕机(或线程阻塞)，则调用invokeFallBack方法
	 * @Title: doInvoke 
	 * @Description: TODO(描述这个方法的作用) 
	 * @date: 2021年11月25日 下午3:11:12 
	 * @version: 
	 * @return 
	 * @throws
	 */
	@HystrixCommand(fallbackMethod = "invokeFallBack", commandProperties = {
			//// 超时设置
			@HystrixProperty(name = "execution.timeout.enabled", value = "true"),//是否开启断路器
			@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") }//超时时间范围
			, ignoreExceptions = Throwable.class)// 忽略异常，不进入备用方法，异常抛给上层
	public ResponseModel doInvoke() throws Exception {
		// 1.模拟线程阻塞，Hystrix线程阻塞时间默认为1s
		 int sleepTime = new Random().nextInt(3000);
		 logger.info("sleepTime:" + sleepTime);
		 Thread.sleep(sleepTime);

		// 2.模拟异常
		// int i = 1/0;

		long start = System.currentTimeMillis();
		ResponseModel res = feignClient.hello();
		long end = System.currentTimeMillis();
		logger.info("run time: " + (end - start));
		return res;
	}
	
	
	
	/**
	 * Hystrix 限流
	 * @Title: hystrixLimit   
	 * @Description: TODO(描述这个方法的作用)
	 * @date: 2021年12月8日 下午4:18:12   
	 * @version:
	 * @return          
	 * @throws
	 */
	@HystrixCommand(fallbackMethod = "limitFallBack",
			threadPoolKey="goods",
			threadPoolProperties= {
					@HystrixProperty(name="coreSize",value="1"),
					@HystrixProperty(name="maxQueueSize",value="1")
			})
	public ResponseModel hystrixLimit() {
		return feignClient.hello();
	}

	
	/**
	 * Hystrix 服务降级/异常处理
	 * @Title: doInvokeByRibbon   
	 * @Description: TODO(描述这个方法的作用)
	 * @date: 2021年12月8日 下午4:18:26   
	 * @version:
	 * @return
	 * @throws Exception          
	 * @throws
	 */
	@HystrixCommand(fallbackMethod = "invokeFallBack")
	public String doInvokeByRibbon() throws Exception {
		// 1.模拟线程阻塞，Hystrix线程阻塞时间默认为1s
		// int sleepTime = new Random().nextInt(3000);
		// logger.info("sleepTime:" + sleepTime);
		// Thread.sleep(sleepTime);

		// 2.模拟异常
		// int i = 1/0;

		long start = System.currentTimeMillis();
		String res = restTemplate.getForObject("http://eureka-provider/provider/hello", String.class);
		long end = System.currentTimeMillis();
		logger.info("run time: " + (end - start));
		return res;
	}

	/**
	 * @Title: invokeFallBack 
	 * @Description:Hystrix异常处理（ 当远程服务异常时，调用备用方法）
	 * @date:2021年12月2日 下午3:59:18 
	 * @version: 
	 * @param throwable 
	 * @return 
	 * @throws
	 */
	public ResponseModel invokeFallBack(Throwable throwable) {
		throwable.printStackTrace();// 捕获异常
		return ResponseModel.errorMsg("调用失败，服务已降级处理！");
	}
	
	
	/**
	 * 限流服务降级处理
	 * @Title: limitFallBack   
	 * @Description: TODO(描述这个方法的作用)
	 * @date: 2021年12月8日 下午4:27:06   
	 * @version:
	 * @param throwable
	 * @return          
	 * @throws
	 */
	public ResponseModel limitFallBack(Throwable throwable) {
		throwable.printStackTrace();// 捕获异常
		return ResponseModel.errorMsg("活动太火爆，请重试");
	}
}
